<template>
  <div class="virtual-list-container" ref="virtualContainer" @scroll="handleScroll">
    <div class="virtual-list-content" :style="{marginTop:`${marginTopHeight}px`}">
      <div v-for="item in sourceArray" class="item">
        <slot :item="item">item:{{ item }}</slot>
      </div>
      <div class="virtual-list-loading" v-show="loading">加载中...</div>
    </div>
  </div>
</template>

<script>
let oldOffset = 0
export default {
  name: "virtual-list",
  props: {
    itemHeight: {
      type: Number,
      default: 45
    },
    dataSource: {
      type: Array,
      default: []
    },
    preLoadCount: {
      type: Number,
      default: 2
    },
    scrollToEnd: {
      type: Function
    },
  },
  data() {
    return {
      containerHeight: 0,
      count: 0,
      //sourceArray: [],
      showRange: {
        start: 0,
        end: 0
      },
      marginTopHeight: 0,
      loading: false,
      scrollTopOffset: 0 //剩余偏移量
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.containerHeight = this.$refs.virtualContainer.offsetHeight
      this.count = Math.ceil(this.containerHeight / this.itemHeight)
      this.scrollTopOffset = this.count * this.itemHeight - this.$refs.virtualContainer.offsetHeight
      this.showRange = {
        start: 0,
        end: this.count * 2 + this.preLoadCount
      }
    })
  },
  computed: {
    sourceArray: function () {
      return this.dataSource.slice(this.showRange.start, this.showRange.end)
    },
  },
  methods: {
    handleScroll() {
      const offset = Math.floor(this.$refs.virtualContainer.scrollTop / this.itemHeight)
      if (offset !== oldOffset) {
        // console.log(this.$refs.virtualContainer.scrollTop)
        // console.log(this.$refs.virtualContainer.offsetHeight)
        // console.log(this.$refs.virtualContainer.scrollHeight)
        // console.log(offset, oldOffset)
        const isDown = offset >= oldOffset // 判断是上拉还是下拉
        oldOffset = offset
        const startSize = offset - this.preLoadCount;
        const endSize = this.count + offset + this.preLoadCount;
        this.showRange = {
          start: startSize > 0 ? startSize : 0,
          end: endSize < this.dataSource.length ? endSize : this.dataSource.length
        }
        this.marginTopHeight = this.showRange.start * this.itemHeight
        if (this.$refs.virtualContainer.scrollTop + this.$refs.virtualContainer.offsetHeight + this.scrollTopOffset >= this.dataSource.length * this.itemHeight) {
          if (this.scrollToEnd && isDown) {
            this.scrollToEnd(this.callback)
            this.loading = true
          }
        }
      }
    },
    callback(success) {
      this.marginTopHeight = this.marginTopHeight + this.itemHeight
      this.loading = false
    },
    scrollToTop() {
      this.$refs.virtualContainer.scrollTo({top: 0})
    }
  }
}
</script>

<style scoped>
.virtual-list-container {
  height: 100%;
  width: 100%;
  overflow: auto;
  background: greenyellow;
}

.virtual-list-content {
  width: 100%;
  background: aqua;
}

.item {
  border: 1px black solid;
  box-sizing: border-box;
  height: 45px;
  width: 100%;
}

.virtual-list-loading {
  text-align: center;
  padding: 12px 0;
}
</style>
